#include <jni.h>
#include <string>
#include <android/log.h>
#include <malloc.h>

extern "C"
{
#include  "librtmp/rtmp.h"
}
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"well",__VA_ARGS__)

// 用于保存 sps、pps 结构体
typedef struct {
    RTMP *rtmp;
    int8_t *sps;    // sps数组
    int8_t *pps;    // pps数组
    int16_t sps_len;// sps数组长度
    int16_t pps_len;// pps数组长度
} Live;
Live *live = nullptr;

// 链接rtmp服务器
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_np_rtmpdump1_ScreenLive_connect(JNIEnv *env, jobject thiz, jstring url_) {
    const char *url = env->GetStringUTFChars(url_, 0);
    int ret;

    // 不断重试，链接服务器
    do {
        //初始化live数据
        live = (Live *) malloc(sizeof(Live));
        //清空live数据
        memset(live, 0, sizeof(Live));
        //初始化RTMP,申请内存
        live->rtmp = RTMP_Alloc();
        RTMP_Init(live->rtmp);
        //设置超时时间
        live->rtmp->Link.timeout = 10;
        //设置地址
        LOGI("rtmpdump connect RTMP_SetupURL %s", url);
        if (!(ret = RTMP_SetupURL(live->rtmp, (char *) url))) break;
        //设置输出模式
        LOGI("rtmpdump connect RTMP_EnableWrite");
        RTMP_EnableWrite(live->rtmp);
        //连接
        LOGI("rtmpdump connect RTMP_Connect");
        if (!(ret = RTMP_Connect(live->rtmp, 0))) break;
        //连接流
        LOGI("rtmpdump connect RTMP_ConnectStream");
        if (!(ret = RTMP_ConnectStream(live->rtmp, 0))) break;
        LOGI("rtmpdump connect success");
    } while (0);

    //连接失败，释放内存
    if (!ret && live) {
        free(live);
        live = nullptr;
    }

    env->ReleaseStringUTFChars(url_, url);
    return ret;
}

int sendPacket(RTMPPacket *packet) {
    int r = RTMP_SendPacket(live->rtmp, packet, 1);
    RTMPPacket_Free(packet);
    free(packet);
    return r;
}

void prepareVideo(int8_t *data, int len, Live *live) {
    for (int i = 0; i < len; i++) {
        //0x00 0x00 0x00 0x01
        if (i + 4 < len) {
            if (data[i] == 0x00 && data[i + 1] == 0x00
                && data[i + 2] == 0x00
                && data[i + 3] == 0x01) {
                //0x00 0x00 0x00 0x01 7 sps 0x00 0x00 0x00 0x01 8 pps
                //将sps pps分开
                //找到pps
                if (data[i + 4] == 0x68) {
                    //去掉界定符
                    live->sps_len = i - 4;
                    live->sps = static_cast<int8_t *>(malloc(live->sps_len));
                    memcpy(live->sps, data + 4, live->sps_len);

                    live->pps_len = len - (4 + live->sps_len) - 4;
                    live->pps = static_cast<int8_t *>(malloc(live->pps_len));
                    memcpy(live->pps, data + 4 + live->sps_len + 4, live->pps_len);
                    LOGI("sps:%d pps:%d", live->sps_len, live->pps_len);
                    break;
                }
            }
        }
    }
}

// 视频数据封包
RTMPPacket *createVideoPackage(int8_t *buf, int len, const long tms, Live *live) {
//    分隔符被抛弃了      --buf指的是651
    buf += 4;
    len -= 4;
    int body_size = len + 9;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(packet, len + 9);

    packet->m_body[0] = 0x27;
    if (buf[0] == 0x65) { //关键帧
        packet->m_body[0] = 0x17;
        LOGI("发送关键帧 data");
    }
    packet->m_body[1] = 0x01;
    packet->m_body[2] = 0x00;
    packet->m_body[3] = 0x00;
    packet->m_body[4] = 0x00;
    //长度
    packet->m_body[5] = (len >> 24) & 0xff;
    packet->m_body[6] = (len >> 16) & 0xff;
    packet->m_body[7] = (len >> 8) & 0xff;
    packet->m_body[8] = (len) & 0xff;

    //数据
    memcpy(&packet->m_body[9], buf, len);

    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    packet->m_nChannel = 0x04;
    packet->m_nTimeStamp = tms;
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

// sps、pps 封包
RTMPPacket *createVideoPackage(Live *live) {
    int body_size = 13 + live->sps_len + 3 + live->pps_len;
    RTMPPacket *packet = (RTMPPacket *) malloc(sizeof(RTMPPacket));
    RTMPPacket_Alloc(packet, body_size);
    int i = 0;
    //AVC sequence header 与IDR一样
    packet->m_body[i++] = 0x17;
    //AVC sequence header 设置为0x00
    packet->m_body[i++] = 0x00;
    //CompositionTime
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    packet->m_body[i++] = 0x00;
    //AVC sequence header
    packet->m_body[i++] = 0x01;   //configurationVersion 版本号 1
    packet->m_body[i++] = live->sps[1]; //profile 如baseline、main、 high

    packet->m_body[i++] = live->sps[2]; //profile_compatibility 兼容性
    packet->m_body[i++] = live->sps[3]; //profile level
    packet->m_body[i++] = 0xFF; // reserved（111111） + lengthSizeMinusOne（2位 nal 长度） 总是0xff
    //sps
    packet->m_body[i++] = 0xE1; //reserved（111） + lengthSizeMinusOne（5位 sps 个数） 总是0xe1
    //sps length 2字节
    packet->m_body[i++] = (live->sps_len >> 8) & 0xff; //第0个字节
    packet->m_body[i++] = live->sps_len & 0xff;        //第1个字节
    memcpy(&packet->m_body[i], live->sps, live->sps_len);
    i += live->sps_len;

    /*pps*/
    packet->m_body[i++] = 0x01; //pps number
    //pps length
    packet->m_body[i++] = (live->pps_len >> 8) & 0xff;
    packet->m_body[i++] = live->pps_len & 0xff;
    memcpy(&packet->m_body[i], live->pps, live->pps_len);

    packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;
    packet->m_nBodySize = body_size;
    packet->m_nChannel = 0x04;
    packet->m_nTimeStamp = 0;
    packet->m_hasAbsTimestamp = 0;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet->m_nInfoField2 = live->rtmp->m_stream_id;
    return packet;
}

int sendVideo(int8_t *buf, int len, long tms) {
    int ret;
    if (buf[4] == 0x67) {
        // H264某帧的第五个字节是67，那么该帧包含的是 sps pps
        if (live && (!live->pps || !live->sps)) {
            prepareVideo(buf, len, live);
        }
    } else {
        if (buf[4] == 0x65) {
            // H264某帧的第五个字节是65，那么该帧为I帧

            // 创建 sps、pps 数据包
            RTMPPacket *packet = createVideoPackage(live);
            // 在发送I帧之前，发送 sps、pps 数据包
            if (!(ret = sendPacket(packet))) {}
        }

        // 创建I帧数据包
        RTMPPacket *packet = createVideoPackage(buf, len, tms, live);
        // 发送I帧数据包
        ret = sendPacket(packet);
    }
    return ret;
}

// 发送数据到rtmp服务器
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_np_rtmpdump1_ScreenLive_sendData(JNIEnv *env, jobject thiz, jbyteArray data_, jint len,
                                              jlong tms, jint type) {
    // 确保不会取出空的 RTMP 数据包
    if (!data_) {
        return 0;
    }
    int ret;
    int8_t *data = env->GetByteArrayElements(data_, NULL);

    if (type == 1) {//视频
        LOGI("开始发送视频 %d", len);
        ret = sendVideo(data, len, tms);
    } else {//音频
        LOGI("开始发送音频 %d", len);
        //ret = sendAudio(data, len, tms, type);
    }

    env->ReleaseByteArrayElements(data_, data, 0);
    return ret;
}